#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "zq_gl.h"
#include "safe_base64.h"
#include "self_test.h"

static char selftest_report_str[1024];
SelftestReportItems *selftest_report_p = (SelftestReportItems *)selftest_report_str;

// static uint32_t selftest_start_time_stamp = 0;
static uint16_t selftest_tmp_time_point[ST_RECORD_SIZE] = {0};
static uint8_t selftest_tmp[ST_RECORD_SIZE] = {0};
static uint16_t selftest_comp_time_point[ST_RECORD_SIZE] = {0};

// 在给定的time_point_queue队列末尾加入一个时间标点，成功返回队列中的记录数量(时间点和时区的和)，失败返回0
// 队列中时间的记录方式为, 记录从起始时间(cat1_startup_time)以来的分钟数;
// 每个记录为1byte，最大记录到240，超过240就插入一个时区标志(0xff), 所以: 记录中 0xff的个数为n, 具体值为v, 表示时间为n*240+v
// 例如: 2000/01/01 00:00:00开始， 数据记录为 0x64, 0xff, 0x00, 0x02, 0xff, 0x01...第n个0xff, v1, v2... 
// static int AddTimePoint(uint8_t *time_point_queue)
// {
//     uint32_t span = ZqGetUTCStample() - selftest_report_p->cat1_startup_time;
//     if(span > 24*3600)
//         return 0;
//     uint8_t zone_level = span / 240;
//     uint8_t time_point = span % 240;

//     for(int i = 0; i < ST_RECORD_SIZE; i++){
//         if(time_point_queue[i] == 0) {
//             if(zone_level > 0) {
//                 zone_level--;
//                 time_point_queue[i] = ST_TIME_ZONE_FLAG;
//                 continue;
//             }
//             else {
//                 time_point_queue[i] = time_point;
//                 return i + 1;
//             }
//         }
//         else if(time_point_queue[i] == 0xff && zone_level > 0){
//             zone_level--;
//         }
//     }
// } 

// reset and init all report data
void Selftest_Init(uint32_t start_time_stamp)
{
    memset(selftest_report_p, 0, sizeof(SelftestReportItems));
    selftest_report_p->version = 1;
    selftest_report_p->cat1_startup_time = ZqGetUTCStample();
}
bool Selftest_AddTmpTimePoint(uint16_t tmp)
{
    if(selftest_report_p->tem_num >= ST_RECORD_SIZE)
        return false;
    uint32_t span = ZqGetUTCStample() - selftest_report_p->cat1_startup_time;
    if(span > 24*3600)
        return false;

    uint8_t tmp_integer = (tmp >= 0) ? ((tmp + 5) / 10) : ((tmp - 5) / 10);      // 四舍五入
    selftest_tmp_time_point[selftest_report_p->tem_num] = (uint16_t)(span / 60);
    selftest_tmp[selftest_report_p->tem_num] = tmp_integer;
    selftest_report_p->tem_num++;
    return true;
}
bool Selftest_AddCompTimePoint(void)
{
    if(selftest_report_p->comp_num >= ST_RECORD_SIZE)
        return false;
    uint32_t span = ZqGetUTCStample() - selftest_report_p->cat1_startup_time;
    if(span > 24*3600)
        return false;

    selftest_comp_time_point[selftest_report_p->comp_num] = (uint16_t)(span / 60);
    selftest_report_p->comp_num++;
    return true;
}

// get a url-safe base64 string from the current report data
char * Selftest_GetReport(void)
{
    uint8_t buf[1024/4*3];
    int i = sizeof(SelftestReportItems);

    uint8_t *p = (uint8_t *)selftest_report_p;
    memcpy(buf, p, i);

    // pack temperature points
    for(int j = 0; j < selftest_report_p->tem_num; j++) {
        (*p++) = selftest_tmp[j];
    }
    // pack temporature change time points
    for(int j = 0, zone_level = 0; j < selftest_report_p->tem_num; j++) {
        while((selftest_tmp_time_point[j] / ST_TIME_ZONE_SIZE) > zone_level) {
            (*p++) = ST_TIME_ZONE_FLAG;
            zone_level++;
        }
        (*p++) = selftest_tmp_time_point[j] % ST_TIME_ZONE_SIZE;
    }
    // pack compressor switch time points
    for(int j = 0, zone_level = 0; j < selftest_report_p->comp_num; j++) {
        while((selftest_comp_time_point[j] / ST_TIME_ZONE_SIZE) > zone_level) {
            (*p++) = ST_TIME_ZONE_FLAG;
            zone_level++;
        }
        (*p++) = selftest_comp_time_point[j] % ST_TIME_ZONE_SIZE;
    }

    base64_encode_binary((uint8_t *)selftest_report_p, p - (uint8_t *)selftest_report_p, selftest_report_str);
    return selftest_report_str;
}